using Microsoft.Synchronization.Data;
using Newtonsoft.Json;
using Syncronization.REST;
using System.IO;

namespace Syncronization.Common
{
    public class mfLYSyncRequest
    {
        #region Properties

        /// <summary>
        /// Gets or sets the group metadata.
        /// </summary>
        /// <value>The group metadata.</value>
        public mfLYGroupMetadata GroupMetadata { get; set; }

        /// <summary>
        /// Gets or sets the session.
        /// </summary>
        /// <value>The session.</value>
        public mfLYSyncSession Session { get; set; }

        /// <summary>
        /// Gets or sets the data set.
        /// </summary>
        /// <value>The data set.</value>
        public string DataSet { get; set; }

        #endregion

        #region public

        /// <summary>
        /// Creates the sync request.
        /// </summary>
        /// <param name="groupMetadata">The group metadata.</param>
        /// <param name="syncSession">The sync session.</param>
        /// <returns></returns>
        public static mfLYSyncRequest CreateSyncRequest(SyncGroupMetadata groupMetadata, SyncSession syncSession)
        {
            var syncRequest = new mfLYSyncRequest();
            CreateSyncSession(syncRequest, syncSession);
            CreateGroupMetaData(syncRequest, groupMetadata);
            return syncRequest;
        }


        /// <summary>
        /// Creates the sync request.
        /// </summary>
        /// <param name="groupMetadata">The group metadata.</param>
        /// <param name="syncSession">The sync session.</param>
        /// <param name="dataSet">The data set.</param>
        /// <param name="serializer">The serializer.</param>
        /// <returns></returns>
        public static mfLYSyncRequest CreateSyncRequest(SyncGroupMetadata groupMetadata, SyncSession syncSession, System.Data.DataSet dataSet,
            JsonSerializer serializer)
        {
            var syncRequest = CreateSyncRequest(groupMetadata, syncSession);

            serializer.Converters.Add(new DataSetConverter());

            using (TextWriter textWriter = new StringWriter())
            {
                using (JsonWriter writer = new JsonTextWriter(textWriter))
                {
                    serializer.Serialize(writer, dataSet);
                }
                syncRequest.DataSet = textWriter.ToString();
            }
            return syncRequest;
        }

        /// <summary>
        /// Gets the sync group metadata.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <returns></returns>
        public static SyncGroupMetadata GetSyncGroupMetadata(mfLYSyncRequest request)
        {
            var groupMetaData = new SyncGroupMetadata(request.GroupMetadata.GroupName);
            groupMetaData.BatchCount = request.GroupMetadata.BatchCount;

            groupMetaData.MaxAnchor = new SyncAnchor(request.GroupMetadata.MaxAnchor);
            groupMetaData.NewAnchor = new SyncAnchor(request.GroupMetadata.NewAnchor);

            int tableCount = request.GroupMetadata.TablesMetadata.Length;

            for (int i = 0; i < tableCount; i++)
            {
                var syncTable = new SyncTableMetadata();
                syncTable.TableName = request.GroupMetadata.TablesMetadata[i].TableName;
                syncTable.LastReceivedAnchor =
                    new SyncAnchor(request.GroupMetadata.TablesMetadata[i].LastReceivedAnchor);
                syncTable.LastSentAnchor =
                    new SyncAnchor(request.GroupMetadata.TablesMetadata[i].LastSentAnchor);

                string direction = request.GroupMetadata.TablesMetadata[i].SyncDirection;

                //don't use enum.parse here.  CF has a huge pref hit for enum.parse :(
                if (direction == "Bidirectional")
                {
                    syncTable.SyncDirection = SyncDirection.Bidirectional;
                }
                else if (direction == "DownloadOnly")
                {
                    syncTable.SyncDirection = SyncDirection.DownloadOnly;
                }
                else if (direction == "Snapshot")
                {
                    syncTable.SyncDirection = SyncDirection.Snapshot;
                }
                else if (direction == "UploadOnly")
                {
                    syncTable.SyncDirection = SyncDirection.UploadOnly;
                }

                groupMetaData.TablesMetadata.Add(syncTable);
            }

            return groupMetaData;
        }

        /// <summary>
        /// Gets the sync session.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <returns></returns>
        public static SyncSession GetSyncSession(mfLYSyncRequest request)
        {
            var syncSession = new SyncSession
                                  {
                                      ClientId = request.Session.ClientId,
                                      OriginatorId = request.Session.OriginatorId
                                  };

            int parameterCount = request.Session.Parameters.Length;

            for (int i = 0; i < parameterCount; i++)
            {
                var parameter = new SyncParameter
                                    {
                                        Name = request.Session.Parameters[i].Name,
                                        Value = request.Session.Parameters[i].Value
                                    };
                syncSession.SyncParameters.Add(parameter);
            }

            return syncSession;
        }

        #endregion

        #region private

        private static void CreateGroupMetaData(mfLYSyncRequest syncRequest, SyncGroupMetadata groupMetadata)
        {
            syncRequest.GroupMetadata = new mfLYGroupMetadata
                                            {GroupName = groupMetadata.GroupName, BatchCount = groupMetadata.BatchCount};

            if (groupMetadata.NewAnchor != null)
                syncRequest.GroupMetadata.NewAnchor = groupMetadata.NewAnchor.Anchor;

            if (groupMetadata.MaxAnchor != null)
                syncRequest.GroupMetadata.MaxAnchor = groupMetadata.MaxAnchor.Anchor;

            int tableCount = groupMetadata.TablesMetadata.Count;
            syncRequest.GroupMetadata.TablesMetadata = new mfLYSyncTableMetadata[tableCount];

            for (int i = 0; i < tableCount; i++)
            {
                var syncTable = new mfLYSyncTableMetadata();
                syncTable.TableName = groupMetadata.TablesMetadata[i].TableName;
                syncTable.LastReceivedAnchor = groupMetadata.TablesMetadata[i].LastReceivedAnchor.Anchor;
                syncTable.LastSentAnchor = groupMetadata.TablesMetadata[i].LastSentAnchor.Anchor;
                syncTable.SyncDirection = groupMetadata.TablesMetadata[i].SyncDirection.ToString();
                syncRequest.GroupMetadata.TablesMetadata[i] = syncTable;
            }
        }

        private static void CreateSyncSession(mfLYSyncRequest syncRequest, SyncSession syncSession)
        {
            syncRequest.Session = new mfLYSyncSession
                                      {
                                          ClientId = syncSession.ClientId,
                                          SessionId = syncSession.SessionId,
                                          OriginatorId = syncSession.OriginatorId
                                      };

            int parameterCount = syncSession.SyncParameters.Count;
            syncRequest.Session.Parameters = new mfLYSyncParameter[parameterCount];

            for (int i = 0; i < parameterCount; i++)
            {
                var parameter = new mfLYSyncParameter
                                    {
                                        Name = syncSession.SyncParameters[i].Name,
                                        Value = syncSession.SyncParameters[i].Value
                                    };
                syncRequest.Session.Parameters[i] = parameter;
            }
        }

        #endregion

       
    }
}